#include <ClanLib-2.0/ClanLib/display.h>
#include <ClanLib-2.0/ClanLib/sound.h>

/*Тестовый сорец, просто потомок глобального класса Object.
 * Выпилить list<Unit*> из парента после тестов!*/

#include "unit.h"
#include "world.h"

#include "missile.h" //Missile file from Sprite RTS

#ifndef WIN32
// For rand()
#include <stdlib.h>
#endif

Unit::Unit(World *world) : Object()
{
	this->world = world;

	CL_GraphicContext gc = world->get_gc();

	sprMove = new CL_Sprite(gc, "SpaceShootBodyMoving", &world->resources);
	sprStill = new CL_Sprite(gc, "SpaceShootBodyStill", &world->resources);
	sprTurretStill = new CL_Sprite(gc, "SpaceShootTurretStill", &world->resources);
	sprTurretShooting = new CL_Sprite(gc, "SpaceShootTurretShooting", &world->resources);
	sprTurretReloading = new CL_Sprite(gc, "SpaceShootTurretReloading", &world->resources);
	sprTurretGunFlash = new CL_Sprite(gc, "SpaceShootTurretGunFlash", &world->resources);

	csprCollision = new CL_CollisionOutline("Gfx/spaceshoot_body_still1.png");
	csprCollision->set_alignment(origin_center);

	speed = 100.0f;
	turn_speed = 80.0f;
	turret_turn_speed = 150.0f;

	angle = dest_angle = delta_angle = 0.0f;

	reverse = selected = is_firing = false;

	sprMain = sprStill;
	sprTurret = sprTurretStill;
}

Unit::~Unit()
{
	delete sprMain, sprMove, sprStill, csprCollision, sprTurret, sprTurretStill,
		sprTurretShooting, sprTurretReloading, sprTurretGunFlash;
}

//***Collision detection
bool Unit::HitCheck(CL_CollisionOutline *outline, Object *with)
{
	return csprCollision->collide(*outline);
}

bool Unit::HitCheck(int x, int y)
{
	int width = sprMain->get_width();
	int height = sprMain->get_height();

	return (x >= this->x - width / 2 && x <= this->x + width / 2 && y >= this->y - height / 2 && y <= this->y + height / 2);
}

//***Positions && Angles
void Unit::SetPos(int x, int y)
{
	this->x = dx = (float)x;
	this->y = dy = (float)y;

	csprCollision->set_translation(this->x, this->y);
}

void Unit::SetAngle(float angle)
{
	this->angle = angle;
	csprCollision->set_angle(CL_Angle(angle, cl_degrees));
}

void Unit::SetTurretAngle(float angle)
{
	turret_angle = angle;
}

//***Remote positions && angles
void Unit::SetDest(int x, int y)
{
	dx = (float)x;
	dy = (float)y;

	CL_Vec2f vector(this->x - dx, this->y - dy);
	CL_Vec2f up(0.0f, 1.0f);

	float tmp = up.angle(vector).to_degrees();
	if (x < this->x)
		tmp = 360.0f - tmp;

	SetDestAngle(tmp);

	vector.normalize();
	delta_x = -vector.x;
	delta_y = -vector.y;

	sprMain = sprMove; //Moving
}

void Unit::SetDestAngle(float angle)
{
	dest_angle = angle;
	delta_angle = dest_angle - this->angle;

	if (delta_angle > 180.0f)
	{
		delta_angle -= 360.0f;
		this->angle += 360.0f;
	}

	if (delta_angle < -180.0f)
	{
		delta_angle += 360.0f;
		this->angle -= 360.0f;
	}
}

void Unit::SetTurretDest(int x, int y)
{
	CL_Vec2f vector(this->x - x, this->y - y);
	CL_Vec2f up(0.0f, 1.0f);

	float tmp = up.angle(vector).to_degrees();
	if (x < this->x)
		tmp = 360.0f - tmp;

	SetDestTurretAngle(tmp);
}

void Unit::SetDestTurretAngle(float dest_angle)
{
	dest_turret_angle = dest_angle;
	delta_turret_angle = dest_turret_angle - turret_angle;

	if (delta_turret_angle > 180.0f)
	{
		delta_turret_angle -= 360.0f;
		turret_angle += 360.0f;
	}

	if (delta_turret_angle < -180.0f)
	{
		delta_turret_angle += 360.0f;
		turret_angle -= 360.0f;
	}
}

//***Game moments
void Unit::SetHP(int new_hp)
{
	if (new_hp > 0)
		hp = new_hp;
}

void Unit::Damage(int dmg)
{
	if (dmg > 0 && dmg <= hp)
		hp -= dmg;
}

void Unit::Fire()
{
	if (is_firing == false)
	{
		sprTurret = sprTurretShooting;
		sprTurretShooting->restart();

		is_firing = true;

		for (int i = 0; i < 360; i += 360)
		{
			Missile *missile = new Missile(world, this);
			missile->setPos((int)x, (int)y);
			missile->setSpeed(1000.0f);
			missile->setAngle(turret_angle + i);
			missile->move(43);
			world->AddObject(missile);
		}
	}
}

//***Render functions
void Unit::draw()
{
	CL_GraphicContext gc = world->get_gc();
	sprMain->draw(gc, x, y);
	sprTurret->draw(gc, x, y);
}

bool Unit::update(float time)
{
	sprMain->update(time);
	sprTurret->update(time);

	if (sprTurretShooting->is_finished() && sprTurret == sprTurretShooting)
	{
		sprTurret = sprTurretReloading;
		sprTurretReloading->restart();
	}
	else if (sprTurretReloading->is_finished() && sprTurret == sprTurretReloading)
	{
		sprTurret = sprTurretStill;
		sprTurretStill->restart();

		is_firing = false;
	}

	//Unit corpse turn
	if (delta_angle > 0.0f)
	{
		angle += turn_speed * time;
		if (angle > dest_angle)
		{
			angle = dest_angle;
			delta_angle = 0.0f;
		}
	}
	else
	{
		angle -= turn_speed * time;
		if (angle < dest_angle)
		{
			angle = dest_angle;
			delta_angle = 0.0f;
		}
	}

	//Turret corpse turn
	if (delta_turret_angle > 0.0f)
	{
		turret_angle += turret_turn_speed * time;
		if (turret_angle > dest_turret_angle)
		{
			turret_angle = dest_turret_angle;
			delta_turret_angle = 0.0f;
		}
	}
	else
	{
		turret_angle -= turret_turn_speed * time;
		if (turret_angle < dest_turret_angle)
		{
			turret_angle = dest_turret_angle;
			delta_turret_angle = 0.0f;
		}
	}

	//Unit move
	if (delta_angle == 0.0f)
	{
		if (dx != x || dy != y)
		{
			x += delta_x * speed * time;
			y += delta_y * speed * time;
			csprCollision->set_translation(x, y);

			if ((delta_x > 0 && x > dx) || (delta_x < 0 && x < dx))
				x = dx;
			if ((delta_y > 0 && y > dy) || (delta_y < 0 && y < dy))
				y = dy;

			if (x == dx && y == dy)
			{
				sprMain = sprStill;
				reverse = false;
			}
		}
	}

	sprMain->set_angle(CL_Angle(angle, cl_degrees));
	sprTurret->set_angle(CL_Angle(turret_angle, cl_degrees));
	sprTurretGunFlash->set_angle(CL_Angle(turret_angle, cl_degrees));

	csprCollision->set_angle(CL_Angle(angle, cl_degrees));

	if (!reverse && world->HitCheck(csprCollision, this))
	{
		SetDest(
			int(x + cos((CL_PI / 180.0f) * (angle + 90 + int(rand() % 60) - 30)) * 30),
			int(y + sin((CL_PI / 180.0f) * (angle + 90 + int(rand() % 60) - 30)) * 30));

		reverse = true;
	}

	if (world->HitCheck(csprCollision, this))
		CL_Console::write_line("LOL");

	if (hp > 0) //Health points check
		return true;
	else
		return false; // (hp > 0) ? return true : return false; - does't work : (
}

